package page_rank

import (
	"math/rand"
	"time"
)

type tRandomWalkPageRanking struct {
}

var gPossiblityToLinkedPage = 85

func newRandomWalkPageRanking() IPageRanking {
	return &tRandomWalkPageRanking{}
}

func (me *tRandomWalkPageRanking) RankAll(pages []IPage, rounds int) {
	iPageCount := len(pages)
	if iPageCount <= 0 {
		return
	}

	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	current := pages[0]

	iVisitCount := iPageCount * rounds
	for i := 0;i < iVisitCount;i++ {
		// visit current page
		current.SetWeight(current.GetWeight() + 1)

		possibility := r.Intn(100)
		if possibility < gPossiblityToLinkedPage && len(current.GetLinks())>0 {
			// goto linked page
			current = me.VisitLinkedPage(current, r)

		} else {
			// goto unlinked page
			current = me.VisitUnlinkedPage(current, pages, r)
		}
	}

	fVisitCount := float64(iVisitCount)
	for _,p := range pages {
		p.SetWeight(p.GetWeight() / fVisitCount)
	}
}


func (me *tRandomWalkPageRanking) VisitLinkedPage(current IPage, r *rand.Rand) IPage {
	links := current.GetLinks()
	next := links[r.Intn(len(links))]
	return next
}

func (me *tRandomWalkPageRanking) VisitUnlinkedPage(current IPage, pages []IPage, r *rand.Rand) IPage {
	mapLinks := make(map[string]bool, 0)
	mapLinks[current.ID()] = true
	for _,p := range current.GetLinks() {
		mapLinks[p.ID()] = true
	}

	n := len(pages)
	for {
		next := pages[r.Intn(n)]
		if _,ok := mapLinks[next.ID()];!ok {
			return next
		}
	}
}

var RandomWalkPageRanking = newRandomWalkPageRanking()